{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 最小二乘蒙特卡洛美式期权定价的基本原理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1.美式期权的特点\n",
    "\n",
    "\n",
    "美式期权的持有者可以在期权到期之前的任意时刻行使期权，因此在每个时间点，持有者需要决定是立即行使期权还是继续持有以等待未来的潜在收益。\n",
    "\n",
    "2.蒙特卡洛资产价格路径模拟\n",
    "\n",
    "蒙特卡洛模拟生成大量可能的未来资产价格路径。在这些路径上，每个时间点的资产价格都会对应不同的可能的未来现金流。对于每条路径，在每个时间点都需要做出是否行使期权的决策。\n",
    "\n",
    "3.未来现金流的回归\n",
    "\n",
    "在每个时间点，我们想要估计如果继续持有期权，预期收益是多少。为了做出这个估计，我们可以回顾未来的现金流，并根据当前的市场条件进行回归。\n",
    "自变量：当前的资产价格以及可能影响未来收益的其他因子（例如波动率、利率等）。\n",
    "因变量：未来现金流的折现值，即在未来某一时刻行使期权所能获得的现金流，折现回当前时间点。\n",
    "通过对这些模拟路径进行回归，我们可以得到当前时间点的“持有价值”的估计。\n",
    "\n",
    "4.回归的意义\n",
    "\n",
    "回归的目的是为了捕捉当前资产价格与未来现金流之间的关系。通过回归得到的模型，我们能够预测在当前市场条件下，如果继续持有期权，其未来可能的收益是多少。\n",
    "\n",
    "5.决策过程\n",
    "\n",
    "在每个时间点，比较期权的立即行使价值（即执行期权所能得到的现金流）和继续持有的预期收益。如果继续持有的预期收益更高，那么最优策略就是继续持有；否则，应该立即行使期权。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "# import numba\n",
    "import pandas as pd\n",
    "import scipy.stats as stats\n",
    "\n",
    "plt.rcParams[\"font.sans-serif\"] = [\"SimHei\"]  # 用来正常显示中文标签\n",
    "plt.rcParams[\"axes.unicode_minus\"] = False  # 正常显示负号"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "假设我们要对美式看跌期权估值，行权价为1.1，标的价格为1，无风险利率为6%，模拟的价格路径如下。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>t=0</th>\n",
       "      <th>t=1</th>\n",
       "      <th>t=2</th>\n",
       "      <th>t=3</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Path</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1.0</td>\n",
       "      <td>1.09</td>\n",
       "      <td>1.08</td>\n",
       "      <td>1.34</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1.0</td>\n",
       "      <td>1.16</td>\n",
       "      <td>1.26</td>\n",
       "      <td>1.54</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1.0</td>\n",
       "      <td>1.22</td>\n",
       "      <td>1.07</td>\n",
       "      <td>1.03</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1.0</td>\n",
       "      <td>0.93</td>\n",
       "      <td>0.97</td>\n",
       "      <td>0.92</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>1.0</td>\n",
       "      <td>1.11</td>\n",
       "      <td>1.56</td>\n",
       "      <td>1.52</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>1.0</td>\n",
       "      <td>0.76</td>\n",
       "      <td>0.77</td>\n",
       "      <td>0.90</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>1.0</td>\n",
       "      <td>0.92</td>\n",
       "      <td>0.84</td>\n",
       "      <td>1.01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>1.0</td>\n",
       "      <td>0.88</td>\n",
       "      <td>1.22</td>\n",
       "      <td>1.34</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      t=0   t=1   t=2   t=3\n",
       "Path                       \n",
       "1     1.0  1.09  1.08  1.34\n",
       "2     1.0  1.16  1.26  1.54\n",
       "3     1.0  1.22  1.07  1.03\n",
       "4     1.0  0.93  0.97  0.92\n",
       "5     1.0  1.11  1.56  1.52\n",
       "6     1.0  0.76  0.77  0.90\n",
       "7     1.0  0.92  0.84  1.01\n",
       "8     1.0  0.88  1.22  1.34"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "S_path = pd.DataFrame(\n",
    "    data={\n",
    "        \"Path\": np.arange(1, 9),\n",
    "        \"t=0\": np.ones(8),\n",
    "        \"t=1\": np.array([1.09, 1.16, 1.22, 0.93, 1.11, 0.76, 0.92, 0.88]),\n",
    "        \"t=2\": np.array([1.08, 1.26, 1.07, 0.97, 1.56, 0.77, 0.84, 1.22]),\n",
    "        \"t=3\": np.array([1.34, 1.54, 1.03, 0.92, 1.52, 0.90, 1.01, 1.34]),\n",
    "    }\n",
    ")\n",
    "S_path.set_index(\"Path\", inplace=True)\n",
    "S_path"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以计算出相应的内在价值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>t=0</th>\n",
       "      <th>t=1</th>\n",
       "      <th>t=2</th>\n",
       "      <th>t=3</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Path</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.1</td>\n",
       "      <td>0.01</td>\n",
       "      <td>0.02</td>\n",
       "      <td>0.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.1</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.1</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0.03</td>\n",
       "      <td>0.07</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.1</td>\n",
       "      <td>0.17</td>\n",
       "      <td>0.13</td>\n",
       "      <td>0.18</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.1</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>0.1</td>\n",
       "      <td>0.34</td>\n",
       "      <td>0.33</td>\n",
       "      <td>0.20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>0.1</td>\n",
       "      <td>0.18</td>\n",
       "      <td>0.26</td>\n",
       "      <td>0.09</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>0.1</td>\n",
       "      <td>0.22</td>\n",
       "      <td>0.00</td>\n",
       "      <td>0.00</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      t=0   t=1   t=2   t=3\n",
       "Path                       \n",
       "1     0.1  0.01  0.02  0.00\n",
       "2     0.1  0.00  0.00  0.00\n",
       "3     0.1  0.00  0.03  0.07\n",
       "4     0.1  0.17  0.13  0.18\n",
       "5     0.1  0.00  0.00  0.00\n",
       "6     0.1  0.34  0.33  0.20\n",
       "7     0.1  0.18  0.26  0.09\n",
       "8     0.1  0.22  0.00  0.00"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "exercise_value = np.maximum(1.1 - S_path, 0)\n",
    "exercise_value"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "1.计算到期日t=3的现金流（即到期时期权价值），并折现到t=2\n",
    "\n",
    "2.利用t=2的股票价格作为X，和上一步的现金流作为Y，挑选t=2时点中实值路径（挑选实值路径可以提高效率，网上也有不少人直接利用所有路径去估计的，不过用实值路径效率更佳）,做最小二乘估计得到继续持有期权的价值holding_value。\n",
    "\n",
    "3.比较t=2时点的提前行权价值exercise_value和上一步估计出来的继续持有价值holding_value，exercise_value较大的作为提前行权的标准，在后续计算现金流时，需要用提权行权的价值来计算。 \n",
    "\n",
    "4.重复上述步骤直至t=1 \n",
    "\n",
    "5.将考虑过提前行权的所有路径现金流折现回t=0求均值得到期权价值\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "      X=股票价格  Y=未来现金流折现\n",
      "Path                   \n",
      "1       1.08   0.000000\n",
      "3       1.07   0.065924\n",
      "4       0.97   0.169518\n",
      "6       0.77   0.188353\n",
      "7       0.84   0.084759\n"
     ]
    }
   ],
   "source": [
    "itm_index = exercise_value[\"t=2\"] > 0  # 筛选实值路径\n",
    "X = S_path.loc[itm_index,\"t=2\"]#回归的X为t=2的股票价格，需要注意的是只选取实值路径\n",
    "Y = exercise_value.loc[itm_index,\"t=3\"]*np.exp(-0.06)#回归的Y为t=3的现金流量折现，需要注意的是只选取实值路径\n",
    "reg_data = pd.DataFrame({\"X=股票价格\":X,\"Y=未来现金流折现\":Y})  #这里仅仅是方便列示\n",
    "print(reg_data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "利用XY做回归，计算继续持有价值holding_value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "回归方程\n",
      "-1.814X^2+2.983X -1.070\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>X=股票价格</th>\n",
       "      <th>Y=未来现金流折现</th>\n",
       "      <th>holding_value</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Path</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1.08</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.036741</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1.07</td>\n",
       "      <td>0.065924</td>\n",
       "      <td>0.045898</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.97</td>\n",
       "      <td>0.169518</td>\n",
       "      <td>0.117527</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>0.77</td>\n",
       "      <td>0.188353</td>\n",
       "      <td>0.151969</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>0.84</td>\n",
       "      <td>0.084759</td>\n",
       "      <td>0.156418</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      X=股票价格  Y=未来现金流折现  holding_value\n",
       "Path                                  \n",
       "1       1.08   0.000000       0.036741\n",
       "3       1.07   0.065924       0.045898\n",
       "4       0.97   0.169518       0.117527\n",
       "6       0.77   0.188353       0.151969\n",
       "7       0.84   0.084759       0.156418"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "reg = np.polyfit(x=X, y=Y, deg=2)  # XY做2次最小二乘法\n",
    "print(\n",
    "    f\"回归方程\\n{reg[0]:.3f}X^2+{reg[1]:.3f}X {reg[2]:.3f}\"\n",
    ")  # 输出拟合的回归方程，格式化输出了二次项、一次项和常数项的系数\n",
    "reg_data[\"holding_value\"] = np.polyval(\n",
    "    reg, S_path.loc[itm_index, \"t=2\"]\n",
    ")  # 求出期望的继续持有价值，将计算结果存储在 reg_data 数据框中的holding_value列\n",
    "reg_data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后比较holding_value和行权价值exercise_value，exercise_value大的作为提前行权标准"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>X=股票价格</th>\n",
       "      <th>Y=未来现金流折现</th>\n",
       "      <th>holding_value</th>\n",
       "      <th>exercise_value</th>\n",
       "      <th>early_exercise</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Path</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1.08</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.036741</td>\n",
       "      <td>0.02</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1.07</td>\n",
       "      <td>0.065924</td>\n",
       "      <td>0.045898</td>\n",
       "      <td>0.03</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.97</td>\n",
       "      <td>0.169518</td>\n",
       "      <td>0.117527</td>\n",
       "      <td>0.13</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>0.77</td>\n",
       "      <td>0.188353</td>\n",
       "      <td>0.151969</td>\n",
       "      <td>0.33</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>0.84</td>\n",
       "      <td>0.084759</td>\n",
       "      <td>0.156418</td>\n",
       "      <td>0.26</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      X=股票价格  Y=未来现金流折现  holding_value  exercise_value  early_exercise\n",
       "Path                                                                  \n",
       "1       1.08   0.000000       0.036741            0.02               0\n",
       "3       1.07   0.065924       0.045898            0.03               0\n",
       "4       0.97   0.169518       0.117527            0.13               1\n",
       "6       0.77   0.188353       0.151969            0.33               1\n",
       "7       0.84   0.084759       0.156418            0.26               1"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "reg_data[\"exercise_value\"] = exercise_value.loc[itm_index, \"t=2\"] # 将exercise_value数据框中t=2时期权的实值路径赋值给reg_data数据框的新列 \"exercise_value\"\n",
    "reg_data[\"early_exercise\"] = np.where(\n",
    "    reg_data[\"holding_value\"] < reg_data[\"exercise_value\"], 1, 0   #1表示提前行权，0表示\n",
    ")\n",
    "reg_data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "模型代码逻辑如下：\n",
    "\n",
    "1.计算到期日t的现金流（即到期日期权价值）\n",
    "\n",
    "2.将第1步的现金流折现至前一期t-1，成为t-1日的现金流，然后将其中符合提前行权条件的路径的的现金流替换为提前行权价值\n",
    "\n",
    "3.将第2步得现金流继续往前折现，不断重复。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2.3038226516085225"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 定义几何布朗运动的模拟路径函数\n",
    "def geo_brownian(steps, paths, T, S0, b, sigma):\n",
    "    dt = T / steps  # 求出时间间隔dt\n",
    "    S_path = np.zeros((steps + 1, paths))  # 创建一个矩阵，用来准备储存模拟情况\n",
    "    S_path[0] = S0  # 起点设置\n",
    "    # rn = np.random.standard_normal(S_path.shape) # 也可以一次性创建出需要的正态分布随机数，当然也可以写在循环里每次创建一个时刻的随机数\n",
    "    for step in range(1, steps + 1):\n",
    "        rn = np.random.standard_normal(paths)  # 创造随机数\n",
    "        S_path[step] = S_path[step - 1] * np.exp(\n",
    "            (b - 0.5 * sigma**2) * dt + sigma * np.sqrt(dt) * rn\n",
    "        )  # 几何布朗运动的解\n",
    "    return S_path\n",
    "\n",
    "# 定义最小二乘蒙特卡洛美式期权定价函数\n",
    "def LSM(steps, paths, CP, S0, X, sigma, T, r, b):\n",
    "    S_path = geo_brownian(steps, paths, T, S0, b, sigma)  # 价格生成路径\n",
    "    dt = T / steps\n",
    "    cash_flow = np.zeros_like(S_path)  # 实现创建好现金流量的矩阵，将其元素全部初始化为零，后续使用\n",
    "    df = np.exp(-r * dt)  # 每一期的折现因子\n",
    "    if CP == \"C\":\n",
    "        cash_flow[-1] = np.maximum(\n",
    "            S_path[-1] - X, 0\n",
    "        )  # 先确定最后一期的价值，就是实值额\n",
    "        exercise_value = np.maximum(S_path - X, 0)\n",
    "    else:\n",
    "        cash_flow[-1] = np.maximum(\n",
    "            X - S_path[-1], 0\n",
    "        )  # 先确定最后一期的价值，就是实值额\n",
    "        exercise_value = np.maximum(X - S_path, 0)\n",
    "\n",
    "    # 反向迭代计算每个时间点的现金流\n",
    "    for t in range(steps - 1, 0, -1):  # M-1为倒数第二个时点，从该时点循环至1时点\n",
    "        df_cash_flow = cash_flow[t + 1] * df  # 下一期的现金流的折现值\n",
    "        S_price = S_path[t]  # 标的股价，回归用的X\n",
    "        itm_index = (exercise_value[t] > 0)  # 确定实值的index，后面回归要用，通过index的方式可以不破坏价格和现金流矩阵的大小\n",
    "        reg = np.polyfit(\n",
    "            S_price[itm_index], df_cash_flow[itm_index], 2\n",
    "        )  # 实值路径下的标的股价X和下一期的折现现金流Y回归\n",
    "        holding_value = exercise_value[t].copy()  # 创建一个同长度的向量，为了保持index一致，当然也可以用np.zeros_like等方式，本质一样\n",
    "        holding_value[itm_index] = np.polyval(\n",
    "            reg, S_price[itm_index]\n",
    "        )  # 回归出 holding_value，其他的值虽然等于exercise_value，但是后续判断会去除\n",
    "        ex_index = itm_index & (\n",
    "            exercise_value[t] > holding_value\n",
    "        )  # 在实值路径上，进一步寻找出提前行权的index\n",
    "\n",
    "        df_cash_flow[ex_index] = exercise_value[t][ex_index]  # 将cash_flow中提前行权的替换为行权价值，其他保持下一期折现不变\n",
    "        cash_flow[t] = df_cash_flow  #更新后的现金流 df_cash_flow 存储在 cash_flow 矩阵的对应时间步长位置\n",
    "    value = cash_flow[1].mean() * df\n",
    "    return value\n",
    "\n",
    "\n",
    "LSM(steps=1000, paths=50000, CP=\"P\", S0=40, X=40, sigma=0.2, T=1, r=0.06, b=0.06)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
